#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <vector>
#include <cstdlib>
#include <functional>
#include <sys/wait.h>
#include "Task.hpp"
#include "Channel.hpp"
using work_t = std::function<void()>;

enum
{
    OK = 1,
    UsageError,
    PipeError,
    ForkError
};

class ProcessPool
{
public:
    ProcessPool(int n, work_t w) : processnum(n), work(w)
    {
    }
    // channels:输出型参数
    // work_t work 回调
    int InitProcessPool()
    {
        // 创建指定个数个进程
        for (int i = 0; i < processnum; i++)
        {
            // 1.先有管道
            int pipefd[2] = {0};
            int n = pipe(pipefd);
            if (n < 0)
                return PipeError;
            // 2.创建子进程
            pid_t id = fork();
            if (id < 0)
                return ForkError;
            // 3.建立通信信道
            if (id == 0)
            {
                //关闭历史wfd
                for(auto& c : channels)
                c.Close();
                // child
                ::close(pipefd[1]); // 关闭写端
                dup2(pipefd[0], 0); // 让子进程都从标准输入读取未来的命令，文件重定向
                work();//调用可调用对象
                ::exit(0);
            }
            // 父进程
            ::close(pipefd[0]);                   // 关闭读端
            channels.emplace_back(pipefd[1], id); // 这个id对应的子进程和管道在同一次循环中创建，所以绑定在一起
            // Channel ch(pipefd[1],id);
            // channels.push_back(ch);
        }
        return OK;
    }
    void Dispatchtask()
    {
        int who = 0;
        // 2.派发任务
        int num = 20; // 派发20个任务
        while (num--)
        {
            // a.选择一个任务，整数
            int task = tm.SelectTask();
            // b.选择一个子进程channel,轮询选择子进程
            Channel &curr = channels[who++];
            who %= channels.size();

            std::cout << "####################" << std::endl;
            std::cout << "send " << task << "to" << curr.Name() << ", 任务还剩: " << num << std::endl;
            std::cout << "####################" << std::endl;

            // 派发任务
            curr.Send(task);
            sleep(1);
        }
    }
    void CleanProcessPool()
    {
        //version 2 倒着关
        // for (int i = channels.size(); i >= 0; i--)
        // {
        //     channels[i].Close();
        //     for (auto &c : channels)
        //     {
        //         pid_t rid = ::waitpid(c.Id(), nullptr, 0); // 等待子进程
        //         if (rid > 0)//rid > 0表是顺利等到子进程退出
        //         {
        //             std::cout << "child " << rid << " wait ... success" << std::endl;
        //         }
        //     }
        // }

        //version 1 一次性把写端全关掉
        for (auto &c : channels)
        {
            c.Close();
        }
        for (auto &c : channels)
        {
            pid_t rid = ::waitpid(c.Id(), nullptr, 0); // 等待子进程
            if (rid > 0)
            {
                std::cout << "child " << rid << " wait ... success" << std::endl;
            }
        }
    }
    void DebugPrint()
    {
        for (auto &c : channels)
        {
            std::cout << c.Name() << std::endl;
        }
    }

private:
    std::vector<Channel> channels;  // 组织每个管道的写端
    int processnum;
    work_t work;
};
